{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6d5045d6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/Users/collinsliu/jupyter/machine_learning/chapters/ \n"
     ]
    }
   ],
   "source": [
    "from os import path\n",
    "\n",
    "print(path.abspath(\" \"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "334aedbf",
   "metadata": {},
   "source": [
    "# prepare data - mnist\n",
    "1. two ways:<br>\n",
    "> 1. sklearn fetch_openml <br>\n",
    "> 2. download from official websites <br> arff format"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1800dff7",
   "metadata": {},
   "source": [
    "## Download\n",
    "1. from scipy.io.arff import loadarff\n",
    "2. url: 'https://www.openml.org/data/v1/download/52667/mnist_784.arff'\n",
    "3. mnist_path = \"../data/mnist_784.arff\"\n",
    "4. mnist_raw = loadarff(mnist_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8726521",
   "metadata": {},
   "source": [
    "## Prepare train and test set\n",
    "1. normal ways of splitting training and testing data should be<br>\n",
    "   <font color=maroon><b>sklearn.model_selection.train_test_split</b></font><br>\n",
    "2. also, we could use numpy shuffle and pandas iloc[index]<br>\n",
    "    <font color=maroon><b>shuffle_index=np.random.permutation(length)</b></font><br>\n",
    "    <font color=maroon><b>X=X.iloc[shuffle_index]</b></font><br>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "f1c9fd86-9aff-4665-9416-ab04e402e8b8",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import os\n",
    "import gzip\n",
    "import logging\n",
    "\n",
    "logging.basicConfig(format=\"%(message)s\", level=logging.DEBUG)\n",
    "\n",
    "\n",
    "def parse_mnist(minst_file_addr: str = None, flatten: bool = False, one_hot: bool = False) -> np.array:\n",
    "    \"\"\"解析MNIST二进制文件, 并返回解析结果\n",
    "    输入参数:\n",
    "        minst_file: MNIST数据集的文件地址. 类型: 字符串.\n",
    "        flatten: bool, 默认Fasle. 是否将图片展开, 即(n张, 28, 28)变成(n张, 784)\n",
    "        one_hot: bool, 默认Fasle. 标签是否采用one hot形式.\n",
    "\n",
    "    返回值:\n",
    "        解析后的numpy数组\n",
    "    \"\"\"\n",
    "    if minst_file_addr is not None:\n",
    "        minst_file_name = os.path.basename(minst_file_addr)  # 根据地址获取MNIST文件名字\n",
    "        with gzip.open(filename=minst_file_addr, mode=\"rb\") as minst_file:\n",
    "            mnist_file_content = minst_file.read()\n",
    "        if \"label\" in minst_file_name:  # 传入的为标签二进制编码文件地址\n",
    "            data = np.frombuffer(buffer=mnist_file_content, dtype=np.uint8, offset=8)  # MNIST标签文件的前8个字节为描述性内容，直接从第九个字节开始读取标签，并解析\n",
    "            if one_hot:\n",
    "                data_zeros = np.zeros(shape=(data.size, 10))\n",
    "                for idx, label in enumerate(data):\n",
    "                    data_zeros[idx, label] = 1\n",
    "                data = data_zeros\n",
    "        else:  # 传入的为图片二进制编码文件地址\n",
    "            data = np.frombuffer(buffer=mnist_file_content, dtype=np.uint8, offset=16)  # MNIST图片文件的前16个字节为描述性内容，直接从第九个字节开始读取标签，并解析\n",
    "            data = data.reshape(-1, 784) if flatten else data.reshape(-1, 28, 28)\n",
    "    else:\n",
    "        logging.warning(msg=\"请传入MNIST文件地址!\")\n",
    "\n",
    "    return data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "cb465f92",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(10000,)\n",
      "(10000, 28, 28)\n",
      "(60000,)\n",
      "(60000, 28, 28)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.datasets import fetch_openml\n",
    "\n",
    "# mnist = fetch_openml('mnist_784') \n",
    "test_label_path = '../data/t10k-labels-idx1-ubyte.gz'\n",
    "test_data_path = '../data/t10k-images-idx1-ubyte.gz'\n",
    "train_label_path = '../data/train-labels-idx1-ubyte.gz'\n",
    "train_data_path = '../data/train-images-idx1-ubyte.gz'\n",
    "test_label = parse_mnist(minst_file_addr=test_label_path) \n",
    "test_data = parse_mnist(minst_file_addr=test_data_path) \n",
    "train_label = parse_mnist(minst_file_addr=train_label_path) \n",
    "train_data = parse_mnist(minst_file_addr=train_data_path) \n",
    "print(test_label.shape)\n",
    "print(test_data.shape)\n",
    "print(train_label.shape)\n",
    "print(train_data.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "id": "18546851",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the class of this image is: 3\n"
     ]
    }
   ],
   "source": [
    "import matplotlib\n",
    "import warnings\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "\n",
    "some_digit = train_data[45000,:,:]\n",
    "\n",
    "plt.imshow(some_digit, cmap=plt.cm.binary,interpolation=\"nearest\")\n",
    "plt.axis(\"off\")\n",
    "plt.grid(alpha=0)\n",
    "plt.show()\n",
    "print(\"the class of this image is: {}\".format(train_label[45000]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70452eaf",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "# Binary Classifier - OVA\n",
    "1. <font color=maroon><b>sklearn.linear_model SGDClassifier</b></font> by default is one OVA classifer, for multiple classification problems, algorithm will train corresponding classifiers equal to the number of classes provided, and choose class with the highest score as classification result."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "id": "da33bece",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {color: black;background-color: white;}#sk-container-id-1 pre{padding: 0;}#sk-container-id-1 div.sk-toggleable {background-color: white;}#sk-container-id-1 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-1 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-1 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-1 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-1 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-1 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-1 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-1 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-1 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-1 div.sk-item {position: relative;z-index: 1;}#sk-container-id-1 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-1 div.sk-item::before, #sk-container-id-1 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-1 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-1 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-1 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-1 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-1 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-1 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-1 div.sk-label-container {text-align: center;}#sk-container-id-1 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-1 div.sk-text-repr-fallback {display: none;}</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>SGDClassifier(random_state=42)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">SGDClassifier</label><div class=\"sk-toggleable__content\"><pre>SGDClassifier(random_state=42)</pre></div></div></div></div></div>"
      ],
      "text/plain": [
       "SGDClassifier(random_state=42)"
      ]
     },
     "execution_count": 119,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.linear_model import SGDClassifier\n",
    "# both numpy ndarray and pandas DataFrame allow masking\n",
    "# being that sifting data with conditional judgement statement\n",
    "###############################################################\n",
    "# in this case, label will either be 1 or 0 denoting whether \n",
    "# digits belongs to 3 or not 3.\n",
    "# note that category class will store class number as @@str@@\n",
    "# train_label_3 = train_label.apply(lambda x: x == '3')\n",
    "train_label_3 = train_label == 3\n",
    "test_label_3 = test_label == 3\n",
    "# here we choose SGDClassifier\n",
    "# numpy will automatically transfer boolean into int with following pattern\n",
    "# True == 1 | False == 0\n",
    "sgd_clf = SGDClassifier(random_state=42)\n",
    "sgd_clf.fit(train_data.reshape(train_data.shape[0],-1), train_label_3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 139,
   "id": "f1fe231a-9927-485a-a73c-5495087df3ee",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "is this image belongs to class 3? [ True]\n"
     ]
    }
   ],
   "source": [
    "res = sgd_clf.predict(some_digit.flatten().reshape(1,-1))\n",
    "print(\"is this image belongs to class 3? {}\".format(res))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb823e91",
   "metadata": {},
   "source": [
    "# Evaluation - CV\n",
    "basic conception of CV is to test validity of classfier, the average of accuracy will be used to evaluate the effectiveness of algorithm.<br>\n",
    "three main steps are included in one complete process\n",
    "\n",
    "1. split dataset into cv folds\n",
    "2. fit estimator on training set and make prediction on testing set\n",
    "3. calculate corresponding metric score\n",
    "<br>\n",
    "\n",
    "thus, for sklearn provided apis, we could use three different tools for cv<br>\n",
    "## StraitifiedKFold + iteration CV\n",
    "1. mannually implements cross_val_score\n",
    "2. note that <font color=maroon><b>sklearn.model_selection StratifiedKFold</b></font> and  <font color=maroon><b>sklearn.model_selection KFold</b></font> both do CV data preparation with sole difference that the former will do stratified sampling according to class percentage whlie the latter only do consecutive sampling. these two methods are mainly dealing with index, will return index rather than data itself\n",
    "3. clone of estimated classifier is necessary\n",
    "4. <font color=maroon><b>skfolds.split(data, label)</b></font> will return a list of index of each cv sets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 178,
   "id": "133befd4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9430833333333334\n",
      "0.9653333333333334\n",
      "0.9500833333333333\n",
      "0.9649166666666666\n",
      "0.9646666666666667\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import StratifiedKFold\n",
    "from sklearn.model_selection import KFold\n",
    "from sklearn.base import clone\n",
    "\n",
    "skfolds = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n",
    "# Stradified k-fold will split trains set and test set, but in multiple times \n",
    "# this feature is set in n_splits paramter\n",
    "##############################################\n",
    "# sklearn.model_selection could take DataFrame or Series\n",
    "# yet make sure data type being made into @@int@@ or @@float@@\n",
    "# not stayed in None or Object or Boolean\n",
    "for train_index, test_index in skfolds.split(train_data, train_label_3):\n",
    "    # clone is necessary\n",
    "    clone_clf = clone(sgd_clf)\n",
    "    # note that in one iteration of cv, we split train set of total dataset into\n",
    "    # new train set and test set, which is necessary in cv process\n",
    "    X_train_folds = train_data[train_index,:,:]\n",
    "    X_test_fold = train_data[test_index,:,:]\n",
    "    y_train_folds = train_label_3[train_index]\n",
    "    y_test_fold = train_label_3[test_index]\n",
    "    \n",
    "    clone_clf.fit(X_train_folds.reshape(X_train_folds.shape[0],-1), y_train_folds)\n",
    "    # in this case we are calculating accuracy score by hands\n",
    "    # we could also use sklearn.matrics.accuracy for simplified calculation\n",
    "    y_pred = clone_clf.predict(X_test_fold.reshape(X_test_fold.shape[0],-1))\n",
    "    n_correct = sum(y_pred == y_test_fold)\n",
    "    print(n_correct / len(y_pred))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b302a0a8",
   "metadata": {},
   "source": [
    "## cross_val_score CV\n",
    "1. <font color=maroon><b>sklearn.model_selection cross_val_score</b></font> will calculate appointed score for each cv iteration\n",
    "2. <font color=maroon><b>sklearn.model_selection cross_val_predict</b></font> on the other hand will do the prediction process, and later we could use these prediction on assigned metrics for more flexable evaluations<br>\n",
    "   <font color=maroon><b>pred = cross_val_predict(classifier, data, label, cv)</b></font><br>\n",
    "   <font color=maroon><b>scores = score_matrix(data, label)</b></font><br>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 208,
   "id": "1a5ce184",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.92858333, 0.94975   , 0.96316667, 0.96108333, 0.96691667])"
      ]
     },
     "execution_count": 208,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.model_selection import cross_val_score\n",
    "from sklearn.model_selection import cross_validate\n",
    "\n",
    "cross_val_score(sgd_clf, train_data.reshape(train_data.shape[0],-1), \n",
    "                train_label_3, cv=5, scoring=\"accuracy\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b9362cc",
   "metadata": {},
   "source": [
    "## cross_val_predict + metrics CV\n",
    "1. accuracy is not always the best evaluation measurement\n",
    "2. for classification problems, more scoring methods are needed\n",
    "3. <font color=maroon><b>sklearn.metrics confusion_matrix</b></font> confusion matrix will provide accuracy over different categories\n",
    "4. <font color=maroon><b>sklearn.metrics precision_score</b></font>\n",
    "5. <font color=maroon><b>sklearn.metrics recall_score</b></font>\n",
    "6. <font color=maroon><b>sklearn.metrics f1_score</b></font>\n",
    "7. <font color=maroon><b>sklearn.metrics precision_recall_curve</b></font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 188,
   "id": "d831bcd9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[52096,  1773],\n",
       "       [  993,  5138]])"
      ]
     },
     "execution_count": 188,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.linear_model import SGDClassifier\n",
    "from sklearn.model_selection import cross_val_predict\n",
    "from sklearn.metrics import confusion_matrix\n",
    "\n",
    "train_pred = cross_val_predict(sgd_clf, train_data.reshape(train_data.shape[0],-1), train_label_3, cv=5)\n",
    "confusion_matrix(train_label_3,train_pred)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d43f48d",
   "metadata": {},
   "source": [
    "<table style=\"text-align:center;\">\n",
    "    <tr>\n",
    "        <th></th>\n",
    "        <th>pred non-3-class 0</th>\n",
    "        <th>pred 3-class 1</th>\n",
    "    </tr>\n",
    "    <tr>\n",
    "        <td>real non-3-class 0</td>\n",
    "        <td>true non-3-class 0</td>\n",
    "        <td>false positive</td>\n",
    "    </tr>\n",
    "    <tr>\n",
    "        <td>real 3-class 1</td>\n",
    "        <td>false negative</td>\n",
    "        <td>true 3-class 1</td>\n",
    "    </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33b2f0ca",
   "metadata": {},
   "source": [
    "$$ important \\space score \n",
    "\\left\\{\n",
    "\\begin{aligned}\n",
    "    Precision & = & \\frac{True \\space Positive}{all \\space Predicit \\space 1s} & \\\\\n",
    "    Recall & = & \\frac{True \\space Positive}{all \\space Real \\space 1s} & \\\\\n",
    "    F1 & = & \\frac{2}{\\frac{1}{Precision}+\\frac{1}{Recall}}\n",
    "\\end{aligned}\n",
    "\\right .\n",
    "$$ "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 200,
   "id": "2d569ccb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7434524670814643"
      ]
     },
     "execution_count": 200,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import precision_score, recall_score, f1_score\n",
    "# train_pred could only return result of one fold, \n",
    "# which may not show the gerenral result of this model\n",
    "precision_score(train_label_3, train_pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 213,
   "id": "af9adbe0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.8380362094274996"
      ]
     },
     "execution_count": 213,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "recall_score(train_label_3,train_pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 215,
   "id": "e9086b22",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7879159638092317"
      ]
     },
     "execution_count": 215,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f1_score(train_label_3,train_pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 219,
   "id": "7eb52fc7",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import cross_val_predict\n",
    "from sklearn.metrics import precision_recall_curve\n",
    "\n",
    "# precision_recall will take two params\n",
    "# first is the true labels, for methods to decide label assignments\n",
    "# second is the prediction scores of SGDClassifier\n",
    "y_scores = cross_val_predict(sgd_clf, train_data.reshape(train_data.shape[0],-1), \n",
    "                             train_label_3,cv = 3,method=\"decision_function\")\n",
    "precision, recalls, threshold = precision_recall_curve(train_label_3, y_scores)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 221,
   "id": "1353e920",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_precision_recall(precisions, recalls, thresholds):\n",
    "    plt.plot(thresholds, precisions[:-1],\n",
    "             color=\"blue\",ls='--',lw=1,label=\"Precision\")\n",
    "    plt.plot(thresholds, recalls[:-1],\n",
    "             color=\"purple\",ls='-',lw=1,label=\"Recall\")\n",
    "    plt.xlabel(\"Threshold\")\n",
    "    plt.legend(loc=\"upper left\")\n",
    "    plt.grid(alpha=0.4)\n",
    "    plt.ylim([0,1])\n",
    "    plt.xlim([-55000,55000])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 223,
   "id": "7cd21ab3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_precision_recall(precision, recalls, threshold)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6442d873",
   "metadata": {},
   "source": [
    "# Multiclass Classifier - OVO\n",
    "1. SGDClassifier could detect a OvA training need - show trainig score is <font color=sapphire><b>decision_function</b></font> attribute\n",
    "2. else, use sklearn.multiclass OneVsOneClassifier - <font color=sapphire><b>estimators_ attribute</b></font> will show each underlying estimator\n",
    "3. other classifier could do multiclass classification\n",
    "\n",
    "## Create OVO on SGDClassifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 232,
   "id": "41403a8a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([3], dtype=uint8)"
      ]
     },
     "execution_count": 232,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.linear_model import SGDClassifier\n",
    "from sklearn.model_selection import cross_val_score\n",
    "import warnings \n",
    "\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "sgd_clf.fit(train_data.reshape(train_data.shape[0],-1), train_label)\n",
    "sgd_clf.predict(some_digit.reshape(1,-1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 240,
   "id": "bc203eb7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "class-0 score:-25092.399481053086\n",
      "class-1 score:-16993.941178031702\n",
      "class-2 score:-8864.701156417235\n",
      "class-3 score:7305.562886497098\n",
      "class-4 score:-16887.37082659073\n",
      "class-5 score:-4858.877598279283\n",
      "class-6 score:-19167.00348555122\n",
      "class-7 score:-13902.607006367834\n",
      "class-8 score:-2698.1148759160005\n",
      "class-9 score:-4561.964844074366\n"
     ]
    }
   ],
   "source": [
    "warnings.filterwarnings(\"ignore\")\n",
    "some_digit_scores = sgd_clf.decision_function(some_digit.reshape(1,-1))\n",
    "for cls,scr in zip(sgd_clf.classes_, some_digit_scores.flatten()):\n",
    "    print(\"class-{} score:{}\".format(cls,scr))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 244,
   "id": "0de7e406",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([3], dtype=uint8)"
      ]
     },
     "execution_count": 244,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.multiclass import OneVsOneClassifier\n",
    "\n",
    "ovo_clf = OneVsOneClassifier(SGDClassifier(random_state=42,shuffle=True))\n",
    "ovo_clf.fit(train_data.reshape(train_data.shape[0],-1), train_label)\n",
    "ovo_clf.predict(some_digit.reshape(1,-1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 251,
   "id": "41e9231a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "class-0 score:0.6666671243494753\n",
      "class-1 score:3.666668040028584\n",
      "class-2 score:3.6666711021560645\n",
      "class-3 score:9.333333086507347\n",
      "class-4 score:2.666667073418233\n",
      "class-5 score:8.333332992445767\n",
      "class-6 score:0.6666670041727325\n",
      "class-7 score:3.6666680621072407\n",
      "class-8 score:7.333332832305942\n",
      "class-9 score:4.3333299513612795\n"
     ]
    }
   ],
   "source": [
    "some_digit_score_ovo = ovo_clf.decision_function(some_digit.reshape(1,-1))\n",
    "for cls,scr in zip(sgd_clf.classes_, some_digit_score_ovo.flatten()):\n",
    "    print(\"class-{} score:{}\".format(cls,scr))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3fe84c4",
   "metadata": {},
   "source": [
    "## Create OVO on RandomForest Classifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 256,
   "id": "345db934",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([3], dtype=uint8)"
      ]
     },
     "execution_count": 256,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.ensemble import RandomForestClassifier\n",
    "\n",
    "forest_clf = RandomForestClassifier()\n",
    "forest_clf.fit(train_data.reshape(train_data.shape[0],-1),train_label)\n",
    "forest_clf.predict(some_digit.reshape(1,-1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 258,
   "id": "5d945db4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 :  0.0\n",
      "1 :  0.0\n",
      "2 :  0.0\n",
      "3 :  0.98\n",
      "4 :  0.0\n",
      "5 :  0.01\n",
      "6 :  0.0\n",
      "7 :  0.0\n",
      "8 :  0.01\n",
      "9 :  0.0\n"
     ]
    }
   ],
   "source": [
    "forest_proba = forest_clf.predict_proba(some_digit.reshape(1,-1))\n",
    "forest_cla = forest_clf.classes_\n",
    "for cla, proba in zip(forest_cla, forest_proba.flatten()):\n",
    "    print(cla, \": \", proba)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "acc6095b",
   "metadata": {},
   "source": [
    "# Evaluation - CV\n",
    "for evaluating validility of model, we should note that cross_val would not change model itself, also does confusion matrix\n",
    "1. use sklearn.model_selection cross_val_score\n",
    "2. use sklearn.model_selection cross_val_predict\n",
    "2. use sklearn.metrics confusion_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 265,
   "id": "4106d1eb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.96758333, 0.96508333, 0.96391667, 0.964     , 0.97083333])"
      ]
     },
     "execution_count": 265,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.model_selection import cross_val_score\n",
    "\n",
    "std_scaler = StandardScaler()\n",
    "train_scaled = std_scaler.fit_transform(train_data.reshape(train_data.shape[0],-1).astype(np.float64))\n",
    "cross_val_score(forest_clf, train_scaled, train_label,cv=5, scoring='accuracy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 266,
   "id": "3c6be95b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[5851,    1,    8,    2,    3,    8,   18,    0,   30,    2],\n",
       "       [   1, 6645,   37,    9,   11,    4,    5,   12,   12,    6],\n",
       "       [  23,   13, 5761,   27,   30,    3,   18,   36,   36,   11],\n",
       "       [  10,    9,   77, 5823,    3,   62,    8,   46,   68,   25],\n",
       "       [  13,    9,    9,    1, 5658,    2,   28,   14,   17,   91],\n",
       "       [  22,    9,   12,   64,    9, 5210,   39,    5,   35,   16],\n",
       "       [  24,   11,    3,    0,   11,   33, 5820,    0,   16,    0],\n",
       "       [   3,   21,   65,   11,   36,    2,    0, 6035,   15,   77],\n",
       "       [  11,   33,   32,   53,   25,   47,   27,    5, 5556,   62],\n",
       "       [  23,   11,   18,   75,   66,   16,    3,   52,   49, 5636]])"
      ]
     },
     "execution_count": 266,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "from sklearn.model_selection import cross_val_predict\n",
    "\n",
    "train_pred = cross_val_predict(forest_clf, train_scaled, train_label, cv=5)\n",
    "conf_mat = confusion_matrix(train_label ,train_pred)\n",
    "conf_mat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 267,
   "id": "4a844b9d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x152102cd0>"
      ]
     },
     "execution_count": 267,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 480x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.matshow(conf_mat, cmap=plt.get_cmap(\"gray\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 274,
   "id": "ce8aafb7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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/PPPaykpKfc8U86plrVr12pOTk7a5s2b73mGW2nbtq0WERGhaZrtTnVommq0EydO1N566y3t+PHj2oEDB7SXX35Ze+qpp7QjR47c8zw586JPnz7a6dOntQsXLmjPPfecVqZMGa1Ro0baL7/8kq/uXvn555+1cePGaQcPHsz3fK9evbQePXpo586du6d5NE3TpkyZolWqVElr27ZtvvfYqlWrtLp162rbt2+/55lMnTp1Krf529KBAwe0BQsWaI8++qg2fPhw7fz589q5c+e05cuXazVr1tQ2bdpkk1xvvvmmdv/992t16tTRypYtq02bNk3TNE3r2bOnNnDgQE3T7u56Ls3MjAMHDmhOTk7a4sWLtbS0tNznp0+frt133302vzDdunVrrWPHjtqFCxc0TdNssuExderUKa1GjRravn37cp+z5QcccpZPzrW77777TqtZs6b2xx9/2CTPlStXtNq1a2u9evXSnJ2dtb59+2rz5s3TWrZsqc2cOdMmmbKysvJdmM+ZV2FhYVqNGjW069ev3/NMqampmqOjo9aiRYt8zezAgQNa/fr1tS1bttzzTAU1b95ce/PNNzVNu/fXO03FxsZq9913n/b777/nPpfTbGfPnm2TTFlZWVpsbKwWFRWV7zpn3759tZ49e9718eWamRmPPPIIEyZMYNq0aaxcuZLr16+TlJTEr7/+yoABA3BycrJJrpzz4cuWLeOnn35izZo1jB07lh49etjkvw5o+seTd+zYgYuLC4899hgAH374IWPGjOHixYv3PBOQu3xy/i/X+fPnqVKlCh4eHjbJ4+bmRqtWrfj3339Zu3Yta9euxd/fn7p167J+/XqOHTt2zzM5OjpSt27d3McODg5omsbRo0fx9va2yUfPy5cvz8qVK4mPj2fVqlW5z6enp+Po6Iinp+c9z5QjZ3489dRTHDx4kJs3b1KmTBmb5bl69SoeHh64u7vnPpecnExaWhotW7a0SSZHR0e8vLzo0aMH5cqVA+Cvv/7i2LFjDB069O4HuOvt0o698cYbWo0aNbSWLVtq3t7e2kMPPaQdOnTI1rE0TVOfHnRwcNC8vb21H374waZZ3nzzTW38+PHa5s2btbp162rVq1fXfvzxR5tmyjkyXLt2rda0aVObfwQ9Pj4+97R1zlHQn3/+mW/P2lZM51Xjxo21ZcuW2SxLdna21rdv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",
      "text/plain": [
       "<Figure size 480x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "warnings.filterwarnings(\"ignore\")\n",
    "norm_conf_mat = conf_mat / conf_mat.sum(axis=1, keepdims=True)\n",
    "np.fill_diagonal(norm_conf_mat, 0)\n",
    "plt.matshow(norm_conf_mat, cmap=plt.get_cmap('autumn_r'))\n",
    "plt.xticks(range(len(norm_conf_mat)),np.arange(0,10,1),rotation=30)\n",
    "plt.yticks(range(len(norm_conf_mat[0])),np.arange(0,10,1),rotation=30)\n",
    "plt.xlabel(\"predict\")\n",
    "plt.ylabel('real')\n",
    "for x_pos, val in enumerate(norm_conf_mat):\n",
    "    for y_pos , vals in enumerate(val):\n",
    "        plt.text(x_pos, y_pos, np.round(vals,5),\n",
    "                 va='center',ha='center',fontsize=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0ce57158",
   "metadata": {},
   "source": [
    "## investigate each error pair\n",
    "finding out that 4 - 9 pair has more biases\n",
    "1. by picking out corresponding position"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 276,
   "id": "d2f1f0ae",
   "metadata": {},
   "outputs": [],
   "source": [
    "#定义显示一张图片的函数\n",
    "def plot_digit(data):\n",
    "    image=data.reshape(28,28)\n",
    "    plt.imshow(image,cmap=plt.cm.binary,\n",
    "              interpolation=\"nearest\")\n",
    "    plt.axis(\"off\")\n",
    "#定义显示多张图片\n",
    "def plot_digits(instances,images_per_row=10,**options):\n",
    "    size=28\n",
    "    #每行有几个\n",
    "    images_per_row=min(len(instances),images_per_row)\n",
    "    images=instances.values.reshape(len(instances),size,size).tolist()\n",
    "    #有几行\n",
    "    n_rows=(len(instances)-1)//images_per_row+1\n",
    "    row_images=[]\n",
    "    n_empty=n_rows*images_per_row-len(instances)\n",
    "    images.append(np.zeros((size,size*n_empty)))\n",
    "    for row in range(n_rows):\n",
    "        #每次添加一行\n",
    "        rimages=images[row*images_per_row:(row+1)*images_per_row]\n",
    "        # 对添加的每一行的图片左右连接\n",
    "        row_images.append(np.concatenate(rimages,axis=1))\n",
    "    # 对添加的每一列图片 上下连接\n",
    "    image=np.concatenate(row_images,axis=0)\n",
    "    plt.imshow(image,cmap=plt.cm.binary, **options)\n",
    "    plt.axis(\"off\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "52d2feb0",
   "metadata": {},
   "outputs": [],
   "source": [
    "cl_a, cl_b = \"4\", \"9\"\n",
    "X_aa = X_train[(y_train == cl_a) & (y_train_pred == cl_a)]\n",
    "X_ab = X_train[(y_train == cl_a) & (y_train_pred == cl_b)]\n",
    "X_bb = X_train[(y_train == cl_b) & (y_train_pred == cl_b)]\n",
    "X_ba = X_train[(y_train == cl_b) & (y_train_pred == cl_a)]\n",
    "\n",
    "fig, ax = plt.subplots(2,2,figsize=(8,8),\n",
    "                       facecolor='whitesmoke',\n",
    "                       edgecolor='gray')\n",
    "plt.subplot(221);plot_digits(X_aa[:25],images_per_row=5)\n",
    "plt.subplot(222);plot_digits(X_ab[:25],images_per_row=5)\n",
    "plt.subplot(223);plot_digits(X_bb[:25],images_per_row=5)\n",
    "plt.subplot(224);plot_digits(X_ba[:25],images_per_row=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09f72dd1",
   "metadata": {},
   "source": [
    "# Multilabel Classifier\n",
    "1. <font color=maroon><b>sklearn.neighbors KNeighborsClassifier</b></font> could support multilabel classifier\n",
    "2. the usage is create label contains multilabels, which is usually a np array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 280,
   "id": "ca4b652f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-2 {color: black;background-color: white;}#sk-container-id-2 pre{padding: 0;}#sk-container-id-2 div.sk-toggleable {background-color: white;}#sk-container-id-2 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-2 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-2 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-2 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-2 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-2 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-2 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-2 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-2 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-2 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-2 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-2 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-2 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-2 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-2 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-2 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-2 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-2 div.sk-item {position: relative;z-index: 1;}#sk-container-id-2 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-2 div.sk-item::before, #sk-container-id-2 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-2 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-2 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-2 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-2 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-2 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-2 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-2 div.sk-label-container {text-align: center;}#sk-container-id-2 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-2 div.sk-text-repr-fallback {display: none;}</style><div id=\"sk-container-id-2\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>KNeighborsClassifier()</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-2\" type=\"checkbox\" checked><label for=\"sk-estimator-id-2\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">KNeighborsClassifier</label><div class=\"sk-toggleable__content\"><pre>KNeighborsClassifier()</pre></div></div></div></div></div>"
      ],
      "text/plain": [
       "KNeighborsClassifier()"
      ]
     },
     "execution_count": 280,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "\n",
    "y_train_large = (train_label >= 7) # class larger than 7 \n",
    "y_train_odd = (train_label % 2 == 1) # class number is odd\n",
    "y_multilabel = np.concatenate((y_train_large.reshape(len(y_train_large),1), \n",
    "                               y_train_odd.reshape(len(y_train_odd),1)), axis=1)\n",
    "\n",
    "knn_clf = KNeighborsClassifier()\n",
    "knn_clf.fit(train_data.reshape(train_data.shape[0],-1), y_multilabel)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 282,
   "id": "bc71176a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[False,  True]])"
      ]
     },
     "execution_count": 282,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# some_digit is class 3, which should be [False, True]\n",
    "knn_clf.predict(some_digit.reshape(1,-1))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6885f680",
   "metadata": {},
   "source": [
    "## evaluation via f1\n",
    "1. f1 score could count in multi-label manner, with average param needed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 285,
   "id": "1beb8199",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import cross_val_predict\n",
    "from sklearn.metrics import f1_score\n",
    "\n",
    "y_train_knn_pred = cross_val_predict(knn_clf, train_data.reshape(train_data.shape[0],-1),train_label, cv=5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 286,
   "id": "f6bc1db9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9691067721670479"
      ]
     },
     "execution_count": 286,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f1_score(train_label,y_train_knn_pred, average=\"macro\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72ef3f67",
   "metadata": {},
   "source": [
    "# multioutput classifier\n",
    " this could be a little tricky, we regard each pixel as one label, and pixel intensities as classes(0-255) of each label, thus we could have 784 labels per picture in mnist dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "836651f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# first, adding noises to original mnist dataset\n",
    "# when using len to numpy nd array or even pandas DF, it will always return how many rows it would have\n",
    "# in other words, len() will alwasy return first dimension\n",
    "rnd = np.random.RandomState(42)\n",
    "train_noise = rnd.randint(0,100,(len(X_train),784))\n",
    "test_noise = rnd.randint(0,100,(len(X_test),784))\n",
    "X_train_mod = X_train + train_noise\n",
    "X_test_mod = X_test + test_noise\n",
    "y_train_mod = X_train\n",
    "y_test_mod = X_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f31f80b",
   "metadata": {},
   "outputs": [],
   "source": [
    "some_index = 5\n",
    "plot_digit(X_test_mod.iloc[some_index].values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22951278",
   "metadata": {},
   "outputs": [],
   "source": [
    "knn_clf.fit(X_train_mod, y_train_mod)\n",
    "clean_digit = knn_clf.predict([X_test_mod.iloc[some_index]])\n",
    "plot_digit(clean_digit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48c2483d",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "267.188px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
